package com.app.test.leak

import android.graphics.BitmapFactory
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.util.Log
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import com.app.leaktest.R

/**
 * 内存泄漏测试Activity
 * @author lucher
 * @since 2023-05-28
 */
class LeakActivity : AppCompatActivity(), LeakListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)

        //static内存泄漏测试
        testStaticLeak()
        //listener内存泄漏测试
        testListenerLeak()
        //handler内存泄漏测试
        testHandlerLeak()
        //thread内存泄漏测试
        testThreadLeak()
        //非静态内部类泄漏测试
        testInnerClassLeak()

        //加载图片，占用内存，更好的分析内存泄漏
        loadBitmap()
        //退出
        autoFinish()
    }

    /**
     * static内存泄漏测试,此处以toast为例
     * 静态变量的生命周期与app一样，如果不及时释放，就会导致内存泄漏
     */
    private fun testStaticLeak() {
        ToastUtil.show(this, "test1")
        ToastUtil.show(this, "test2")
    }

    /**
     * listener内存泄漏测试（未取消注册）
     * 如果注册了监听，未取消，每次进入都会绑定Activity实例，得不到释放，导致内存泄漏
     */
    private fun testListenerLeak() {
        LeakManager.register(this)
    }

    /**
     * handler内存泄漏测试
     * Handler的生存周期并不会因为你是写在Activity里面就和Activity一样，Activity退出销毁后，也不会回收内存，从而导致泄漏
     */
    private fun testHandlerLeak() {
        var handler: Handler = object : Handler() {
            override fun handleMessage(msg: Message) {
                super.handleMessage(msg)
                Thread {
                    Thread.sleep(60 * 60 * 1000)
                    Log.d("LeakTest", "handleMessage: $msg " + Thread.currentThread().name)
                }
            }
        }
        handler.sendEmptyMessage(0)
    }

    /**
     * 线程内存泄漏测试
     * 临时线程就会拥有Activity的引用，Activity退出销毁后，也不会回收内存，从而导致泄漏
     */
    private fun testThreadLeak() {
        Thread {
            Log.d("LeakTest", "testThreadLeak start " + Thread.currentThread().name)
            Thread.sleep(60 * 60 * 1000)
            Log.d("LeakTest", "testThreadLeak end " + Thread.currentThread().name)
        }.start()
    }

    /**
     * 内部类内存泄漏测试
     */
    private fun testInnerClassLeak() {
        LeakClass().test()
    }

    /**
     * 加载图片，辅助测试
     */
    private fun loadBitmap() {
        var bm = BitmapFactory.decodeResource(resources, R.mipmap.test)
        findViewById<ImageView>(R.id.imageView).setImageBitmap(bm)
    }

    /**
     * 自动退出，辅助测试
     */
    private fun autoFinish() {
        Thread {
            Thread.sleep(300)
            finish()
        }.start()
    }

    override fun callback() {
        Log.d("LeakTest", "callback")
    }

    /**
     * 内部类内存泄漏测试
     * 非静态的内部类会潜在的持有外部类的引用，如果该类做了耗时操作，也会导致Activity得不到释放，引起内存泄漏
     */
    class LeakClass {
        fun test() {
            Thread {
                Log.d("LeakTest", "LeakClass test start " + Thread.currentThread().name)
                Thread.sleep(60 * 60 * 1000)
                Log.d("LeakTest", "LeakClass test end " + Thread.currentThread().name)
            }.start()
        }
    }
}